﻿using System;
using System.Collections.Generic;
using Sandbox.Common.ObjectBuilders;
using Sandbox.Game.Entities;
using Sandbox.ModAPI;
using VRage;
using VRage.Game;
using VRage.Game.Components;
using VRage.Game.Entity;
using VRage.ModAPI;
using VRage.ObjectBuilders;
using VRageMath;

namespace Vicizlat.MultifloorCargoElevator
{
    [MyEntityComponentDescriptor(typeof(MyObjectBuilder_PistonTop), false, "VCZ_Cargo_Elevator_Piston_Top")]
    public class MultifloorCargoElevatorTop : MyGameLogicComponent
    {
        private IMyPistonTop ElevatorTop;
        private int frame = -1;

        private bool InitGears = true;
        private MyEntitySubpart[] Gear = new MyEntitySubpart[4];
        private bool ElevatorSpeedChanged = true;
        private float ElevatorSpeed;
        private float oldElevatorSpeed;
        private MatrixD RotMatrixX;
        private MatrixD FlippedRotMatrixX;
        private Vector3D buttonsOffset;
        private Vector3D forwardDirection;

        public override void Init(MyObjectBuilder_EntityBase objectBuilder)
        {
            NeedsUpdate |= MyEntityUpdateEnum.EACH_FRAME;
            ElevatorTop = (IMyPistonTop)Entity;
        }

        public override void Close() => NeedsUpdate = MyEntityUpdateEnum.NONE;

        public override void UpdateBeforeSimulation()
        {
            try
            {
                if (!ElevatorTop.IsFunctional || ElevatorTop.CubeGrid.Physics == null) return;
                if (ElevatorTop.Piston == null || ElevatorTop.Piston.Closed) return;
                if (frame++ == 299) frame = 0;

                if (frame == 0)
                {
                    if (InitGears)
                    {
                        for (int i = 1; i <= 4; i++) ElevatorTop.TryGetSubpart("gear" + i, out Gear[i - 1]);
                        InitGears = false;
                    }
                    if (Gear[0].Closed || Gear[1].Closed || Gear[2].Closed || Gear[3].Closed)
                    {
                        for (int i = 0; i <= 3; i++) Gear[i].Subparts.Clear();
                        InitGears = true;
                    }
                }
                if (!MyAPIGateway.Utilities.IsDedicated)
                {
                    if (frame == 5 || frame == 65 || frame == 125 || frame == 185 || frame == 245)
                    {
                        ElevatorSpeed = ElevatorTop.Piston.Velocity;
                        if (!ElevatorSpeedChanged) ElevatorSpeedChanged = ElevatorSpeed != oldElevatorSpeed;
                        if (ElevatorSpeedChanged)
                        {
                            RotMatrixX = Matrix.CreateRotationX(ElevatorSpeed / 25);
                            FlippedRotMatrixX = MatrixD.Transpose(RotMatrixX);
                            ElevatorSpeedChanged = false;
                        }
                        oldElevatorSpeed = ElevatorSpeed;
                    }
                    if (ElevatorTop.Piston.Enabled && ElevatorTop.Piston.Velocity != 0)
                    {
                        for (int i = 0; i <= 3; i++)
                        {
                            if (Gear[i] == null) continue;
                            Matrix lm = (i < 2 ? RotMatrixX : FlippedRotMatrixX) * Gear[i].PositionComp.LocalMatrixRef;
                            Gear[i].PositionComp.SetLocalMatrix(ref lm);
                        }
                    }
                }
                if (frame == 15)
                {
                    for (int i = 0; i <= 3; i++)
                    {
                        if (i == 0)
                        {
                            forwardDirection = ElevatorTop.WorldMatrix.Forward;
                            buttonsOffset = (ElevatorTop.WorldMatrix.Up * 2.5f) + (ElevatorTop.WorldMatrix.Forward * 5f) + (ElevatorTop.WorldMatrix.Right * 5f);
                        }
                        if (i == 1)
                        {
                            forwardDirection = ElevatorTop.WorldMatrix.Left;
                            buttonsOffset = (ElevatorTop.WorldMatrix.Up * 2.5f) + (ElevatorTop.WorldMatrix.Forward * 5f) + (ElevatorTop.WorldMatrix.Left * 5f);
                        }
                        if (i == 2)
                        {
                            forwardDirection = ElevatorTop.WorldMatrix.Right;
                            buttonsOffset = (ElevatorTop.WorldMatrix.Up * 2.5f) + (ElevatorTop.WorldMatrix.Backward * 5f) + (ElevatorTop.WorldMatrix.Right * 5f);
                        }
                        if (i == 3)
                        {
                            forwardDirection = ElevatorTop.WorldMatrix.Backward;
                            buttonsOffset = (ElevatorTop.WorldMatrix.Up * 2.5f) + (ElevatorTop.WorldMatrix.Backward * 5f) + (ElevatorTop.WorldMatrix.Left * 5f);
                        }
                        TryAddBlock(ElevatorTop.WorldMatrix.Translation + buttonsOffset, forwardDirection);
                    }
                }
            }
            catch (Exception e)
            {
                Logging.Instance.WriteLine("[ Error in 'MultifloorCargoElevatorTop': " + e.StackTrace + " ]");
            }
        }

        private void TryAddBlock(Vector3D position, Vector3D forward)
        {
            if (ElevatorTop.CubeGrid.CanAddCube(ElevatorTop.CubeGrid.WorldToGridInteger(position)))
            {
                var NewBlockObjectBuilder = new MyObjectBuilder_AdvancedDoor
                {
                    SubtypeName = "VCZ_Cargo_Elevator_Buttons",
                    Owner = ElevatorTop.Piston.OwnerId,
                    BuiltBy = ElevatorTop.Piston.OwnerId,
                };
                var gridBuilder = new MyObjectBuilder_CubeGrid()
                {
                    CreatePhysics = true,
                    GridSizeEnum = ElevatorTop.CubeGrid.GridSizeEnum,
                    PositionAndOrientation = new MyPositionAndOrientation(position, forward, ElevatorTop.WorldMatrix.Up)
                };
                gridBuilder.CubeBlocks.Add(NewBlockObjectBuilder);
                (ElevatorTop.CubeGrid as MyCubeGrid).PasteBlocksToGrid(new List<MyObjectBuilder_CubeGrid> { gridBuilder }, 0, false, true);
            }
        }
    }
}